# -*- coding: utf-8 -*-
#
# Copyright (c) 2012, Rafael Pivato
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of Rafael Pivato nor the names of its contributors
#       may be used to endorse or promote products derived from this
#       software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL RAFAEL PIVATO BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import bcoma
import json
import webapp2
import logging

from wowgae.web import WebHandler
from wowgae.decorators import login_required, membership_required
from wowgae.model import Character
from wowgae.model import AuctionFile
from wowgae.model import CharacterActivation
from wowgae.icon import WowIconLoader


class ActivationHandler(WebHandler):
    """Handles activation requests."""

    @login_required
    def get(self):
        """Shows the user the option to activate one of his/her characters."""
        self.template.use('activation', 'activate')
        data = {'links': self.__links_data()}
        self.template.update(activation=data)
        self.template.write()

    def __links_data(self):
        path = self.request.path
        activation = webapp2.uri_for('activation', self.request)
        activate = activation
        pending = webapp2.uri_for('activation-pending', self.request)
        finished = webapp2.uri_for('activation-finished', self.request)
        if path == activation:
            activation = None
        elif path == pending:
            pending = None
        elif path == finished:
            finished = None
        data = {'activation': activation, 'activate': activate,
                'pending': pending, 'finished': finished}
        return data

    @login_required
    def post(self):
        """Starts the activation process for the given character name."""
        template = self.template
        template.use('activation', 'answer')
        name = self.request.get('name') or 'Unknown'
        character = Character.get_member_by_name(name)
        data = {'character': name.capitalize()}
        if character is None:
            data['successful'] = False
            template.update(character=name.capitalize())
        else:
            activation = CharacterActivation.start(character,
                                                   self.current_user)
            data['successful'] = True
            data['code'] = {
                'golds': activation.golds,
                'silvers': activation.silvers,
                'coppers': activation.coppers,
            }
        data['links'] = self.__links_data()
        template.update(activation=data)
        template.write()

    @login_required
    def get_pending(self):
        """Shows all pending activation codes for current user."""
        self.template.use('activation', 'pending')
        codes = CharacterActivation.get_pending(self.current_user)
        code_data = []
        for code in codes:
            code_data.append({
                'character': code.key().parent().name().capitalize(),
                'golds': code.golds,
                'silvers': code.silvers,
                'coppers': code.coppers,
                'created': code.created,
            })
        code_data = sorted(code_data, key=lambda d: d['character'])
        data = {'pending': code_data, 'links': self.__links_data()}
        self.template.update(activation=data)
        self.template.write()

    @login_required
    def get_finished(self):
        """Shows all characters activated for this account."""
        self.template.use('activation', 'finished')
        characters = Character.get_all_for_account(self.current_account)
        characters_data = []
        main_name = self.current_account and \
                    self.current_account.name.capitalize()
        thumb_url = 'http://us.battle.net/static-render/us/%s'
        for character in characters:
            characters_data.append({
                'name': character.name,
                'main': character.name == main_name,
                'setmain': webapp2.uri_for('activation-set_main',
                                           name=character.name),
                'level': character.level,
                'thumbnail': thumb_url % (character.thumbnail),
                'race': {'icon': WowIconLoader.race_icon(character.race,
                                                         character.gender)},
                'klass': {'icon': WowIconLoader.klass_icon(character.klass)},
            })
        data = {'characters': characters_data, 'links': self.__links_data()}
        self.template.update(activation=data)
        self.template.write()


class SetMainHandler(WebHandler):
    """Adjusts the main character for an account."""

    @membership_required
    def get(self, name):
        """Adjust the main character and redirect to finished list."""
        character = Character.get_by_name(name)
        if character and character.account == self.current_user.user_id():
            self.current_account.change_main(character.name)
        uri = webapp2.uri_for('activation-finished', self.request)
        self.redirect(uri)


class ActivationTask(webapp2.RequestHandler):
    """Processes pending activation codes."""

    def get(self):
        self.post()

    def post(self):
        logging.debug('Starting activation task.')
        try:
            auc_file = bcoma.AuctionFile.fetch_newest('goldrinn')
            model = AuctionFile.get_newest_file()
            if not model or auc_file.last_modified > model.last_modified:

                activations = self.__fetch_activations()
                if activations:

                    logging.debug(('Activation task found %s codes to ' + \
                                   'process.') % (len(activations)))

                    auctions = auc_file.download_data(
                        lambda line:
                            (line[26:30] == '5976') and \
                                bcoma.Auction(
                                    json.loads(line[:line.find('}') + 1])
                                )
                    )

                    if auctions:
                        processed_count = self.__process_auctions(auctions,
                                                                  activations)
                        logging.info(('Activation task found %s auctions ' + \
                                     'and processed %s activations from ' + \
                                     '%s pending.') % (len(auctions),
                                                    processed_count,
                                                    len(activations)))
                    else:
                        logging.info('Activation task found NO auction ' + \
                                     'to process.')
                else:
                    logging.info('Activation task found NO code to process.')

                AuctionFile.put_file(auc_file)
                logging.debug('Activation task marked file as processed.')

            else:
                logging.info('Activation task did not run because the data' + \
                             ' was not fresh.')
        except Exception as ex:
            logging.warn('Activation could not be processed. %s' % (ex))

    def __fetch_activations(self):
        query = CharacterActivation.all()
        iterator = query.run()
        activations = {}
        for activation in iterator:
            char_name = activation.key().parent().name()
            if char_name in activations:
                activations[char_name].append(activation)
            else:
                activations[char_name] = [activation]
        return activations

    def __process_auctions(self, auctions, activations):
        ranks = self.app.config.get('wowgae.ranks')
        processed = 0
        for auction in auctions:
            owner = auction.owner.lower()
            if owner in activations:
                model_list = activations[owner]
                for model in model_list:
                    if model.amount() == auction.buyout or \
                        model.amount() == auction.bid:
                        model.confirm(ranks)
                        processed += 1
        return processed
